﻿
using Xacml.Core;
using Xacml.Core.Interfaces;
using Xacml.Core.Runtime;
using Xacml.Core.Runtime.Functions;
using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Xacml.Core.Runtime.DataTypes
{
  public class DayTimeDuration : IDataType
  {
    private const string PATTERN = "[\\-]?P([0-9]+D(T([0-9]+(H([0-9]+(M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|(\\.[0-9]*)?S)?|M([0-9](\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|\\.[0-9]+S))?|T([0-9]+(H([0-9]+(M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|(\\.[0-9]*)?S)?|M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|\\.[0-9]+S))";
    private const string PATTERN_MATCH = "(?<n>[\\-]?)P((?<d>(\\d+|\\.\\d+|\\d+\\.\\d+))D)?T((?<h>(\\d+|\\.\\d+|\\d+\\.\\d+))H)?((?<m>(\\d+|\\.\\d+|\\d+\\.\\d+))M)?((?<s>(\\d+|\\.\\d+|\\d+\\.\\d+))S)?";
    private string _durationValue;
    private int _days;
    private int _hours;
    private int _minutes;
    private int _seconds;
    private bool _negative;

    public int Days
    {
      get
      {
        if (!this._negative)
          return this._days;
        return this._days * -1;
      }
    }

    public int Hours
    {
      get
      {
        if (!this._negative)
          return this._hours;
        return this._hours * -1;
      }
    }

    public int Minutes
    {
      get
      {
        if (!this._negative)
          return this._minutes;
        return this._minutes * -1;
      }
    }

    public int Seconds
    {
      get
      {
        if (!this._negative)
          return this._seconds;
        return this._seconds * -1;
      }
    }

    public IFunction EqualFunction
    {
      get
      {
        return (IFunction) new DayTimeDurationEqual();
      }
    }

    public IFunction IsInFunction
    {
      get
      {
        return (IFunction) new DayTimeDurationIsIn();
      }
    }

    public IFunction SubsetFunction
    {
      get
      {
        return (IFunction) new DayTimeDurationSubset();
      }
    }

    public string DataTypeName
    {
      get
      {
        return "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration";
      }
    }

    internal DayTimeDuration()
    {
    }

    public DayTimeDuration(string value)
    {
      this._durationValue = value;
      if (new Regex("[\\-]?P([0-9]+D(T([0-9]+(H([0-9]+(M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|(\\.[0-9]*)?S)?|M([0-9](\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|\\.[0-9]+S))?|T([0-9]+(H([0-9]+(M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|(\\.[0-9]*)?S)?|M([0-9]+(\\.[0-9]*)?S|\\.[0-9]+S)?|(\\.[0-9]*)?S)|\\.[0-9]+S))").Match(value).Success)
      {
        Match match = new Regex("(?<n>[\\-]?)P((?<d>(\\d+|\\.\\d+|\\d+\\.\\d+))D)?T((?<h>(\\d+|\\.\\d+|\\d+\\.\\d+))H)?((?<m>(\\d+|\\.\\d+|\\d+\\.\\d+))M)?((?<s>(\\d+|\\.\\d+|\\d+\\.\\d+))S)?").Match(value);
        if (!match.Success)
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_bug]);
        this._negative = match.Groups["n"].Value == "-";
        this._days = int.Parse(match.Groups["d"].Value, (IFormatProvider) CultureInfo.InvariantCulture);
        this._hours = int.Parse(match.Groups["h"].Value, (IFormatProvider) CultureInfo.InvariantCulture);
        this._minutes = int.Parse(match.Groups["m"].Value, (IFormatProvider) CultureInfo.InvariantCulture);
        this._seconds = int.Parse(match.Groups["s"].Value, (IFormatProvider) CultureInfo.InvariantCulture);
      }
      else
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_daytime_duration_value, new object[1]
        {
          (object) value
        }]);
    }

    public override int GetHashCode()
    {
      return base.GetHashCode();
    }

    public override bool Equals(object obj)
    {
      if (!(obj is DayTimeDuration))
        return base.Equals(obj);
      DayTimeDuration dayTimeDuration = (DayTimeDuration) obj;
      if (this._days == dayTimeDuration._days && this._hours == dayTimeDuration._hours && (this._minutes == dayTimeDuration._minutes && this._seconds == dayTimeDuration._seconds))
        return this._negative == dayTimeDuration._negative;
      return false;
    }
  }
}
